#include <spu_mfcio.h>
#include <stdlib.h>
#include <stdio.h>
#include "structs.h"

#define F_(X)		0x##X, 0x##X, 0x##X, 0x##X


#define F_X		0x00, 0x01, 0x02, 0x03
#define F_Y		0x04, 0x05, 0x06, 0x07
#define F_Z		0x08, 0x09, 0x0A, 0x0B
#define F_W		0x0C, 0x0D, 0x0E, 0x0F

#define S_X		0x10, 0x11, 0x12, 0x13
#define S_Y		0x14, 0x15, 0x16, 0x17
#define S_Z		0x18, 0x19, 0x1A, 0x1B
#define S_W		0x1C, 0x1D, 0x1E, 0x1F


#define C16_0       0x80, 0x80, 0x00, 0x01
#define C16_1       0x80, 0x80, 0x02, 0x03
#define C16_2       0x80, 0x80, 0x04, 0x05
#define C16_3       0x80, 0x80, 0x06, 0x07
#define C16_4       0x80, 0x80, 0x08, 0x09
#define C16_5       0x80, 0x80, 0x0A, 0x0B
#define C16_6       0x80, 0x80, 0x0C, 0x0D
#define C16_7       0x80, 0x80, 0x0E, 0x0F

#define N16_0       0x80, 0x80, 0x10, 0x11
#define N16_1       0x80, 0x80, 0x12, 0x13
#define N16_2       0x80, 0x80, 0x14, 0x15
#define N16_3       0x80, 0x80, 0x16, 0x17
#define N16_4       0x80, 0x80, 0x18, 0x19
#define N16_5       0x80, 0x80, 0x1A, 0x1B
#define N16_6       0x80, 0x80, 0x1C, 0x1D
#define N16_7       0x80, 0x80, 0x1E, 0x1F


#define C8_0       0x80, 0x80, 0x80, 0x00
#define C8_1       0x80, 0x80, 0x80, 0x01
#define C8_2       0x80, 0x80, 0x80, 0x02
#define C8_3       0x80, 0x80, 0x80, 0x03
#define C8_4       0x80, 0x80, 0x80, 0x04
#define C8_5       0x80, 0x80, 0x80, 0x05
#define C8_6       0x80, 0x80, 0x80, 0x06
#define C8_7       0x80, 0x80, 0x80, 0x07
#define C8_8       0x80, 0x80, 0x80, 0x08
#define C8_9       0x80, 0x80, 0x80, 0x09
#define C8_A       0x80, 0x80, 0x80, 0x0A
#define C8_B       0x80, 0x80, 0x80, 0x0B
#define C8_C       0x80, 0x80, 0x80, 0x0C
#define C8_D       0x80, 0x80, 0x80, 0x0D
#define C8_E       0x80, 0x80, 0x80, 0x0E
#define C8_F       0x80, 0x80, 0x80, 0x0F

#define N8_0       0x80, 0x80, 0x80, 0x10
#define N8_1       0x80, 0x80, 0x80, 0x11
#define N8_2       0x80, 0x80, 0x80, 0x12
#define N8_3       0x80, 0x80, 0x80, 0x13
#define N8_4       0x80, 0x80, 0x80, 0x14
#define N8_5       0x80, 0x80, 0x80, 0x15
#define N8_6       0x80, 0x80, 0x80, 0x16
#define N8_7       0x80, 0x80, 0x80, 0x17
#define N8_8       0x80, 0x80, 0x80, 0x18
#define N8_9       0x80, 0x80, 0x80, 0x19
#define N8_A       0x80, 0x80, 0x80, 0x1A
#define N8_B       0x80, 0x80, 0x80, 0x1B
#define N8_C       0x80, 0x80, 0x80, 0x1C
#define N8_D       0x80, 0x80, 0x80, 0x1D
#define N8_E       0x80, 0x80, 0x80, 0x1E
#define N8_F       0x80, 0x80, 0x80, 0x1F

#define E_2  0x80, 0x80
#define E_3  0x80, 0x80, 0x80
#define E_4  0x80, 0x80, 0x80, 0x80
#define E_5  0x80, 0x80, 0x80, 0x80, 0x80
#define E_6  0x80, 0x80, 0x80, 0x80, 0x80, 0x80
#define E_7  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80
#define E_8  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80
#define E_9  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80
#define E_10 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80
#define E_11 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80
#define E_12 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80
#define E_13 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80
#define E_14 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80

#define SHUFFLE_MERGE4(A, B, C, D)	(vector unsigned char)(A, B, C, D)

#define SWZ (vector unsigned char)

#define X( A )  spu_shuffle( A, A, SWZ{ F_X, E12 } )
#define Y( A )  spu_shuffle( A, A, SWZ{ F_Y, E12 } )
#define Z( A )  spu_shuffle( A, A, SWZ{ F_Z, E12 } )
#define W( A )  spu_shuffle( A, A, SWZ{ F_W, E12 } )


#define XXXX( A )  spu_shuffle( A, A, SWZ{ F_X, F_X, F_X, F_X } )
#define YYYY( A )  spu_shuffle( A, A, SWZ{ F_Y, F_Y, F_Y, F_Y } )
#define ZZZZ( A )  spu_shuffle( A, A, SWZ{ F_Z, F_Z, F_Z, F_Z } )
#define WWWW( A )  spu_shuffle( A, A, SWZ{ F_W, F_W, F_W, F_W } )
#define YZWX( A )  spu_shuffle( A, A, SWZ{ F_Y, F_Z, F_W, F_X } )
#define ZWXY( A )  spu_shuffle( A, A, SWZ{ F_Z, F_W, F_X, F_Y } )
#define WXYZ( A )  spu_shuffle( A, A, SWZ{ F_W, F_X, F_Y, F_Z } )
#define YXWZ( A )  spu_shuffle( A, A, SWZ{ F_Y, F_X, F_W, F_Z } )

#define YZXW( A )  spu_shuffle( A, A, SWZ{ F_Y, F_Z, F_X, F_W } )
#define ZXYW( A )  spu_shuffle( A, A, SWZ{ F_Z, F_X, F_Y, F_W } )

#define Q16_0( A )  spu_shuffle( A, A, SWZ{ C16_0, E12 } )
#define Q16_1( A )  spu_shuffle( A, A, SWZ{ C16_1, E12 } )
#define Q16_2( A )  spu_shuffle( A, A, SWZ{ C16_2, E12 } )
#define Q16_3( A )  spu_shuffle( A, A, SWZ{ C16_3, E12 } )
#define Q16_4( A )  spu_shuffle( A, A, SWZ{ C16_4, E12 } )
#define Q16_5( A )  spu_shuffle( A, A, SWZ{ C16_5, E12 } )
#define Q16_6( A )  spu_shuffle( A, A, SWZ{ C16_6, E12 } )
#define Q16_7( A )  spu_shuffle( A, A, SWZ{ C16_7, E12 } )

#define NANF (vec_float4){ 1.0f/ 0.0f, 1.0f/ 0.0f, 1.0f/ 0.0f, 1.0f/ 0.0f }

#define ZEROF (vec_float4){ 0.0f, 0.0f, 0.0f, 0.0f }
#define F1111 (vec_float4){ 1.0f, 1.0f, 1.0f, 1.0f }
#define F1000 (vec_float4){ 1.0f, 0.0f, 0.0f, 0.0f }
#define F0100 (vec_float4){ 0.0f, 1.0f, 0.0f, 0.0f }
#define F0010 (vec_float4){ 0.0f, 0.0f, 1.0f, 0.0f }
#define F0001 (vec_float4){ 0.0f, 0.0f, 0.0f, 1.0f }

#define EPSF (vec_float4){ 0.0001f, 0.0001f, 0.0001f, 0.0001f }
#define EPNF (vec_float4){ -0.0001f, -0.0001f, -0.0001f, -0.0001f }

#define V16I (vec_uint4){ 16, 16, 16, 16 }

float inline GetTime( unsigned long long &te )
{
	unsigned long long v = spu_read_decrementer();
	float time = ( te - v ) /  ( 3193000.0f * 25.0f );
	te = v;
	return time;
}


void _D( const vec_int4 & t, const char *str = "", const char *term = "\n" )
{
	for( int i = 0; i < 4; ++i )
	{
		printf( "%d%s", ( (int *)&t)[i], i == 3 ? "":str );
	}
	printf( "%s", term );
};


void _D( const vec_uint4 & t, const char *str = "", const char *term = "\n" )
{
	for( int i = 0; i < 4; ++i )
	{
		printf( "%d%s", ( (unsigned int *)&t)[i], i == 3 ? "":str );
	}
	printf( "%s", term );
};

template<class T> inline T spu_min( const T &a, const T &b )
{
	return  spu_sel( a, b, spu_cmpgt( a, b ) );
}


template<class T> inline T spu_max( const T &a, const T &b )
{
	return  spu_sel( b, a, spu_cmpgt( a, b ) );
}

struct RenderTriangle
{
	vec_int4 minY;
	vec_int4 maxY;
	vec_float4 yL[2];
	vec_float4 wL[2];
	vec_float4 yR[2];
	vec_float4 wR[2];
	vec_uint4   color;
};

#define OFFSET_OF( X, Y )    ( (char *)&(((X *)0)->Y) - ((char *)(0)) )


vec_uchar16 minT[8] =
    {
        { E_4, E_4, E_4, E_4 },//000
        { F_Z, F_Z, F_Z, F_Z },//001
        { F_Y, F_Y, F_Y, F_Y },//010
        { F_Y, F_Y, F_Y, F_Y },//011
        { F_X, F_X, F_X, F_X },//100
        { F_Z, F_Z, F_Z, F_Z },//101
        { F_X, F_X, F_X, F_X },//110
        { F_X, F_X, F_X, F_X } //111
    };


vec_uchar16 tbl1[8] =
    {
        { E_4, E_4, E_4, E_4 },//000
        { F_Z, F_Z, F_Z, F_Z },//001
        { F_Y, F_Y, F_Y, F_Y },//010
        { F_Y, F_Y, F_Y, F_Y },//011
        { F_X, F_X, F_X, F_X },//100
        { F_X, F_X, F_X, F_X },//101
        { F_X, F_X, F_X, F_X },//110
        { F_X, F_X, F_X, F_X } //111
    };



vec_uchar16 tbl2[8] =
    {
        { E_4, E_4, E_4, E_4 },//000
        { F_Z, F_Z, F_Z, F_Z },//001
        { F_Y, F_Y, F_Y, F_Y },//010
        { F_Z, F_Z, F_Z, F_Z },//011
        { F_X, F_X, F_X, F_X },//100
        { F_Z, F_Z, F_Z, F_Z },//101
        { F_Y, F_Y, F_Y, F_Y },//110
        { F_Y, F_Y, F_Y, F_Y } //111
    };

void inline CoRepresent( RenderTriangle &tr, const vec_float4 &x, const vec_float4 &y )
{
	vec_int4 add1 = (vec_int4)si_from_ptr( tbl1 );
	vec_int4 add2 = (vec_int4)si_from_ptr( tbl2 );
	vec_int4 addM = (vec_int4)si_from_ptr( minT );
	vec_float4 xM = y - YZXW( y );
	vec_float4 yM = YZXW( x ) - x;
	vec_float4 iM = spu_re( xM );
	vec_float4 wM = x * xM + y * yM;
	yM = yM * iM;
	wM = wM * iM;

	qword chL = (qword)spu_rl( spu_gather( spu_cmpgt( ZEROF, xM ) ), 3 );
	qword chR = (qword)spu_rl( spu_gather( spu_cmpgt( xM, ZEROF ) ), 3 );

	vec_uchar16 minS = (vec_uchar16)si_lqx( (qword)addM, chL );
	vec_uchar16 maxS = (vec_uchar16)si_lqx( (qword)addM, chR );

	vec_uchar16 rulL0 = (vec_uchar16)si_lqx( (qword)add1, chL );
	vec_uchar16 rulL1 = (vec_uchar16)si_lqx( (qword)add2, chL );

	vec_uchar16 rulR0 = (vec_uchar16)si_lqx( (qword)add1, chR );
	vec_uchar16 rulR1 = (vec_uchar16)si_lqx( (qword)add2, chR );

	vec_float4 minY = (vec_float4)spu_shuffle( (qword)y, (qword)y, minS );
	vec_float4 maxY = (vec_float4)spu_shuffle( (qword)y, (qword)y, maxS );

	tr.yL[0] = (vec_float4)spu_shuffle( (qword)yM, (qword)yM, rulL0 );
	tr.yL[1] = (vec_float4)spu_shuffle( (qword)yM, (qword)yM, rulL1 );

	tr.yR[0] = (vec_float4)spu_shuffle( (qword)yM, (qword)yM, rulR0 );
	tr.yR[1] = (vec_float4)spu_shuffle( (qword)yM, (qword)yM, rulR1 );

	tr.minY = spu_convts( spu_max( ZEROF, minY ), 7 );
	tr.maxY = spu_convts( spu_min( F1111, maxY ), 7 );

	tr.wL[0] = (vec_float4)spu_shuffle( (qword)wM, (qword)wM, rulL0 );
	tr.wL[1] = (vec_float4)spu_shuffle( (qword)wM, (qword)wM, rulL1 );

	tr.wR[0] = (vec_float4)spu_shuffle( (qword)wM, (qword)wM, rulR0 );
	tr.wR[1] = (vec_float4)spu_shuffle( (qword)wM, (qword)wM, rulR1 );

}




struct Line
{
	vec_uint4   color;
	vec_uint4   begAddress;
	vec_uchar16 beg;
	vec_uchar16 begS;
	vec_uchar16 end;
	vec_uchar16 endS;
};

vec_float4 zbuffer[128 + 4][64];

void Init( vec_float4 value )
{
	for( int i = 0; i < 128 * 64; i += 4 )
	{
		zbuffer[0][i + 0] = value;
		zbuffer[0][i + 1] = value;
		zbuffer[0][i + 2] = value;
		zbuffer[0][i + 3] = value;
	}
}

void Print(  )
{

	char *data = ( char *)&zbuffer[0][0];
	for( int i = 0; i < 128; ++i )
	{
		for( int j = 0; j < 256; ++j )
		{
			if( data[ i * 256 * 4 + j * 4 ] )
			{
				printf("*");
			}
			else
			{
				printf(".");
			}
		}
		printf("\n");
	}
};

size_t inline InitIndices( RenderTriangle *tr, size_t number, qword *out )
{
	vec_int4 loop = (vec_int4)si_from_uint( number );
	vec_int4 trPtr = (vec_int4)si_from_ptr( tr );
	vec_int4 ouPtr = (vec_int4)si_from_ptr( out );

	vec_int4 minY = (vec_int4)si_lqd( (qword)trPtr, 0 );
	vec_int4 maxY = (vec_int4)si_lqd( (qword)trPtr, 16 );


	while( 1 )
	{
		vec_uint4 maskR = spu_cmpgt( loop, 0 );
		vec_uint4 maskL = spu_cmpgt( maxY, minY );
		vec_int4 minYN = (vec_int4)si_lqd( (qword)trPtr, 0 + sizeof( RenderTriangle ) );
		vec_int4 maxYN = (vec_int4)si_lqd( (qword)trPtr, 16 + sizeof( RenderTriangle ) );

		if( si_to_uint( (qword)maskR ) == 0 )
		{
			return (qword *)si_to_ptr( (qword)ouPtr ) - out;
		}

		si_stqd( (qword)spu_shuffle( minY, trPtr, SWZ{ F_X, S_X, E_2, E_2 } ), (qword)ouPtr, 0 );
		ouPtr = spu_sel( ouPtr, ouPtr + spu_splats( 16 ),  maskL );
		trPtr = spu_sel( trPtr + spu_splats( (int)sizeof( RenderTriangle ) ), trPtr, maskL );
		
		minY = spu_sel( minYN, minY + spu_splats( 4 ),  maskL );
		maxY = spu_sel(	maxYN, maxY,  maskL );
		loop = spu_sel( loop - spu_splats( 1 ), loop, maskL );
	}

};

void inline InitLines(  Line *lines, qword *in, size_t size )
{
	vec_float4 add = (vec_float4){ 0.5f / 128.0f, 1.5f / 128.0f, 2.5f / 128.0f, 3.5f / 128.0f };

	vec_int4 start = (vec_int4)spu_splats( 0x00010203 );
	
	for( size_t i = 0; i < size; ++i )
	{
		qword rulz = in[i];
		vec_int4 x = (vec_int4)XXXX( rulz );
		RenderTriangle *tr = (RenderTriangle *)si_to_ptr( YYYY( rulz ) );

		vec_float4 y = spu_convtf( x, 7 ) + add;
		
		vec_float4 l0 = tr->wL[0] - y * tr->yL[0];
		vec_float4 l1 = tr->wL[1] - y * tr->yL[1];
		vec_float4 r0 = tr->wR[0] - y * tr->yR[0];
		vec_float4 r1 = tr->wR[1] - y * tr->yR[1];
		

		vec_float4 maxv = spu_min( l0, l1 );
		vec_float4 minv = spu_max( r0, r1 );

	
		vec_int4 a = (vec_int4)spu_convts( maxv, 8 );
		vec_int4 b = (vec_int4)spu_convtu( minv, 8 );

		vec_uint4 m1, m2, m3, m;

		m1 = spu_cmpgt( b, (vec_int4)spu_splats( 255 ) );
		m3 = spu_cmpgt( a, (vec_int4)spu_splats( 255 ) );
		m2 = spu_cmpgt( (vec_int4)spu_splats( 0 ), a );

		a = spu_sel( a, (vec_int4)spu_splats( 255 ), m3 );

		m = spu_or( m1, m2 );
		b = spu_sel( b, (vec_int4)spu_splats( 255 ), m );
		a = spu_sel( a, (vec_int4)spu_splats( 0 ), m );


		vec_int4 amin = spu_min( b, ZWXY( b ) );
		vec_int4 amax = spu_max( a, ZWXY( a ) );
		amin = spu_min( amin, YXWZ( amin ) );
		amax = spu_max( amax, YXWZ( amax ) );


		amin = spu_andc( amin, (vec_int4)spu_splats( 0x7 ) );
		amax = spu_andc( amax, (vec_int4)spu_splats( 0x7 ) );

		lines[i].color = tr->color;
		lines[i].begAddress = (vec_uint4)( (vec_int4)si_from_ptr( &zbuffer[0][0] ) + spu_rl( amin, 2 ) + spu_rl( x, 10 )  );
		lines[i].begS = (vec_uchar16)spu_shuffle( b, b, SWZ { F_(3), F_(7), F_(B), F_(F) } );
		lines[i].beg  = (vec_uchar16)( start + spu_shuffle( amin, amin, SWZ { F_(3), F_(3), F_(3), F_(3) } ) );
		lines[i].endS = (vec_uchar16)spu_shuffle( a, a, SWZ { F_(3), F_(7), F_(B), F_(F) } );
		lines[i].end  = (vec_uchar16)spu_shuffle( amax, amax, SWZ { F_(3), F_(3), F_(3), F_(3) } );

	}

};


size_t inline InitLines( Line *lines, RenderTriangle &tr )
{
	vec_float4 add = (vec_float4){ 0.5f / 128.0f, 1.5f / 128.0f, 2.5f / 128.0f, 3.5f / 128.0f };

	vec_int4 start = (vec_int4)spu_splats( 0x00010203 );
	int lMin = si_to_uint( (qword) tr.minY  );
	int lMax = si_to_uint( (qword) tr.maxY  );
	int j = 0;

	vec_float4 y =  spu_convtf( tr.minY, 7 ) + add;

	vec_float4 l0 = tr.wL[0] - y * tr.yL[0];
	vec_float4 l1 = tr.wL[1] - y * tr.yL[1];
	vec_float4 r0 = tr.wR[0] - y * tr.yR[0];
	vec_float4 r1 = tr.wR[1] - y * tr.yR[1];

	for( int i = lMin; i < lMax; i += 4 )
	{

		y = y + spu_splats( 4.0f / 128.0f );

		vec_float4 maxv = spu_min( l0, l1 );
		vec_float4 minv = spu_max( r0, r1 );

		l0 = tr.wL[0] - y * tr.yL[0];
		l1 = tr.wL[1] - y * tr.yL[1];
		r0 = tr.wR[0] - y * tr.yR[0];
		r1 = tr.wR[1] - y * tr.yR[1];

		vec_int4 a = (vec_int4)spu_convts( maxv, 8 );
		vec_int4 b = (vec_int4)spu_convtu( minv, 8 );

		vec_uint4 m1, m2, m3, m;

		m1 = spu_cmpgt( b, (vec_int4)spu_splats( 255 ) );
		m3 = spu_cmpgt( a, (vec_int4)spu_splats( 255 ) );
		m2 = spu_cmpgt( (vec_int4)spu_splats( 0 ), a );

		a = spu_sel( a, (vec_int4)spu_splats( 255 ), m3 );

		m = spu_or( m1, m2 );
		b = spu_sel( b, (vec_int4)spu_splats( 255 ), m );
		a = spu_sel( a, (vec_int4)spu_splats( 0 ), m );


		vec_int4 amin = spu_min( b, ZWXY( b ) );
		vec_int4 amax = spu_max( a, ZWXY( a ) );
		amin = spu_min( amin, YXWZ( amin ) );
		amax = spu_max( amax, YXWZ( amax ) );


		amin = spu_andc( amin, (vec_int4)spu_splats( 0x7 ) );
		amax = spu_andc( amax, (vec_int4)spu_splats( 0x7 ) );

		lines[j].color = tr.color;
		lines[j].begAddress = (vec_uint4)( (vec_int4)si_from_ptr( &zbuffer[i][0] ) + spu_rl( amin, 2 ) );
		lines[j].begS = (vec_uchar16)spu_shuffle( b, b, SWZ { F_(3), F_(7), F_(B), F_(F) } );
		lines[j].beg  = (vec_uchar16)( start + spu_shuffle( amin, amin, SWZ { F_(3), F_(3), F_(3), F_(3) } ) );
		lines[j].endS = (vec_uchar16)spu_shuffle( a, a, SWZ { F_(3), F_(7), F_(B), F_(F) } );
		lines[j].end  = (vec_uchar16)spu_shuffle( amax, amax, SWZ { F_(3), F_(3), F_(3), F_(3) } );
		++j;

	}
	return j;

};

size_t inline DoLines( Line *lines, size_t cnt )
{
	size_t lptr = 0;
	int cntQ = 0;

	vec_uchar16   xx = lines[0].beg;
	vec_uint4   to = lines[0].begAddress;
	vec_uint4   lp = (vec_uint4)spu_splats( 0 );


	while( lptr < cnt )
	{
		++cntQ;

		Line &line = lines[lptr];
		Line &lineNext = lines[lptr + 1];
		vec_uint4 clr = line.color;

		vec_uchar16 yx = (vec_uchar16)spu_add( (vec_uint4)xx, (vec_uint4)spu_splats( 0x04040404 ) );
		vec_uchar16 end = spu_cmpgt( line.end, xx );
		vec_uint4 toAdd = spu_add( to, (vec_uint4)spu_splats( 32 ) );
		vec_uint4 lpAdd = spu_add( lp, (vec_uint4)spu_splats( 1 ) );
		vec_uchar16 xxAdd = (vec_uchar16)spu_add(  (vec_uint4)xx, (vec_uint4)spu_splats( 0x08080808 ) );

		vec_uchar16 b1 = spu_cmpgt( line.begS, xx );
		vec_uchar16 b5 = spu_cmpgt( line.begS, yx );
		vec_uchar16 e1 = spu_cmpgt( xx,	line.endS  );
		vec_uchar16 e5 = spu_cmpgt( yx, line.endS  );
		e1 = spu_nor( b1, e1 );
		e5 = spu_nor( b5, e5 );


		vec_uint4 d1 = (vec_uint4)si_lqd( (qword)to, 0 * 16 * 64 );
		vec_uint4 d2 = (vec_uint4)si_lqd( (qword)to, 1 * 16 * 64 );
		vec_uint4 d3 = (vec_uint4)si_lqd( (qword)to, 2 * 16 * 64 );
		vec_uint4 d4 = (vec_uint4)si_lqd( (qword)to, 3 * 16 * 64 );
		vec_uint4 d5 = (vec_uint4)si_lqd( (qword)to, 0 * 16 * 64 + 16 );
		vec_uint4 d6 = (vec_uint4)si_lqd( (qword)to, 1 * 16 * 64 + 16 );
		vec_uint4 d7 = (vec_uint4)si_lqd( (qword)to, 2 * 16 * 64 + 16 );
		vec_uint4 d8 = (vec_uint4)si_lqd( (qword)to, 3 * 16 * 64 + 16 );

		qword oto = (qword)to;
		to = spu_sel( lineNext.begAddress, toAdd, end );
		lp = spu_sel( lpAdd, lp, end );
		xx = spu_sel( lineNext.beg, xxAdd, end );


		d1 = spu_sel( d1, clr, (vec_uint4)spu_shuffle( e1, e1, SWZ{ F_(0), F_(1), F_(2), F_(3) } ) );
		d2 = spu_sel( d2, clr, (vec_uint4)spu_shuffle( e1, e1, SWZ{ F_(4), F_(5), F_(6), F_(7) } ) );
		d3 = spu_sel( d3, clr, (vec_uint4)spu_shuffle( e1, e1, SWZ{ F_(8), F_(9), F_(A), F_(B) } ) );
		d4 = spu_sel( d4, clr, (vec_uint4)spu_shuffle( e1, e1, SWZ{ F_(C), F_(D), F_(E), F_(F) } ) );
		d5 = spu_sel( d5, clr, (vec_uint4)spu_shuffle( e5, e5, SWZ{ F_(0), F_(1), F_(2), F_(3) } ) );
		d6 = spu_sel( d6, clr, (vec_uint4)spu_shuffle( e5, e5, SWZ{ F_(4), F_(5), F_(6), F_(7) } ) );
		d7 = spu_sel( d7, clr, (vec_uint4)spu_shuffle( e5, e5, SWZ{ F_(8), F_(9), F_(A), F_(B) } ) );
		d8 = spu_sel( d8, clr, (vec_uint4)spu_shuffle( e5, e5, SWZ{ F_(C), F_(D), F_(E), F_(F) } ) );


		/*
		d1 = spu_or( (vec_uint4)spu_splats( 0x40103020 ), d1 );
		d2 = spu_or( (vec_uint4)spu_splats( 0x40103020 ), d2 );
		d3 = spu_or( (vec_uint4)spu_splats( 0x40103020 ), d3 );
		d4 = spu_or( (vec_uint4)spu_splats( 0x40103020 ), d4 );
		d5 = spu_or( (vec_uint4)spu_splats( 0x40103020 ), d5 );
		d6 = spu_or( (vec_uint4)spu_splats( 0x40103020 ), d6 );
		d7 = spu_or( (vec_uint4)spu_splats( 0x40103020 ), d7 );
		d8 = spu_or( (vec_uint4)spu_splats( 0x40103020 ), d8 );
		*/


		lptr = si_to_uint( (qword)lp );

		si_stqd( (qword)d1, (qword)oto, 0 * 16 * 64 );
		si_stqd( (qword)d2, (qword)oto, 1 * 16 * 64 );
		si_stqd( (qword)d3, (qword)oto, 2 * 16 * 64 );
		si_stqd( (qword)d4, (qword)oto, 3 * 16 * 64 );
		si_stqd( (qword)d5, (qword)oto, 0 * 16 * 64 + 16 );
		si_stqd( (qword)d6, (qword)oto, 1 * 16 * 64 + 16 );
		si_stqd( (qword)d7, (qword)oto, 2 * 16 * 64 + 16 );
		si_stqd( (qword)d8, (qword)oto, 3 * 16 * 64 + 16 );

	}

	return cntQ;

};

void DumpTile( unsigned int address )
{
	mfc_list_element elements[128];
	//unsigned int address = (unsigned int)pd.frameBuffer + ii * 1024 + jj * 1280 * 4 * 128;

	for( int i = 0; i < 128; ++i )
	{
		elements[i].size = 1024;
		elements[i].eal = address + 1024 * i * 4;
	}

	mfc_putl( &zbuffer[0][0], 0, elements, 1024, 0, 0, 0 );
	mfc_write_tag_mask( 1 );
	mfc_read_tag_status_any();
}

int main(unsigned long long spe_id, unsigned long long program_data_ea, unsigned long long env)
{
	ProgramData pd __attribute__((aligned(16)));
	unsigned long long te;


	//Print();

	spu_write_decrementer( 0xffffffff );



	while( 1 )
	{


		spu_read_in_mbox();
		GetTime( te );

		mfc_get( &pd, program_data_ea, sizeof( pd ), 0, 0, 0 );
		mfc_write_tag_mask( 1 );
		mfc_read_tag_status_any();

		int ii = pd.ii;


		for( int jj = 0; jj < 6; ++jj )
		{

			//float cl1 = GetTime( te );
			Line tbl[32];
	
			Init( spu_splats( 0.0f ) );
			RenderTriangle trs[32];
			GetTime( te );
			for( int i = 0; i < 32; ++i )
			{

				vec_float4 vx = *(vec_float4 *)&pd.tr[i].x;
				vec_float4 vy = *(vec_float4 *)&pd.tr[i].y;


				const int scale = 14;
				vx = spu_convtf( spu_convts( vx, scale ), scale );
				vy = spu_convtf( spu_convts( vy, scale ), scale );

				GetTime( te );
				CoRepresent( trs[i], vx, vy );
				trs[i].color = (vec_uint4)WWWW( vx );

			}


			qword arr[1024];
			
			size_t s = InitIndices( trs, 32, arr );
			size_t r = 0;

			
			for( size_t i = 0; i < s; i += 32 )
			{
				size_t res = s - i;
				res = res > 32 ? 32 : res;
				InitLines( tbl, arr + i, res );
				r += DoLines( tbl, res );
			}

			float cl1 = GetTime( te );
			

			float triangleRate = 16.0f / cl1 / 1000.0f / 1000.0f;
			float pixelRate = 32.0f * r / cl1 / 1000.0f / 1000.0f / 1000.0f;
			float triangleArea = pixelRate / triangleRate * 1000.0f;

			printf( "mtps = %f gpps = %f ppt = %f \n", triangleRate, pixelRate, triangleArea );
		



			DumpTile( (unsigned int)pd.frameBuffer + ii * 1024 + jj * 1024 * 4 * 128 );



		}
		//float cl2 = GetTime( te );
		//printf( "%f\n", cl2 );

		float cl2 = GetTime( te );
		cl2 = 1.0f / cl2;
		//printf( "init %f\n", cl2 );




		spu_write_out_mbox( 3 );
		//
	}
	return 0;
}
